/*
 * GameFinishedGameStateController.cpp
 *
 *  Created on: Jan 20, 2012
 *      Author: rudi
 */
#include <wx/filename.h>
#include <wx/socket.h>
#include "GameFinishedGameStateController.h"
#include "NetworkEventData.h"
#include "SmartPointer.h"
#include "App.h"
#include "MainFrame.h"
#include "MainPanel.h"
#include "IGameController.h"
#include "IdleGameStateController.h"
#include "LevelDownloadingGameStateController.h"
#include "ClientStartingGameStateController.h"
#include "ServerStartingGameStateController.h"
#include "Configuration.h"

GameFinishedGameStateController::GameFinishedGameStateController(): mStaticDrawController(NULL, false)
{
	wxChar pathSeparator = wxFileName::GetPathSeparator();
	wxString level = wxGetApp().getActualLevel();
	wxString imagePath = wxGetCwd() + pathSeparator + wxGetApp().getConfiguration()->getLevels()->getPath() + pathSeparator + level + pathSeparator + level + wxT(".bmp");

	// Draw the level
	mStaticDrawController.setBitmap(new wxBitmap(imagePath, wxBITMAP_TYPE_BMP));
	mStaticDrawController.refreshImage(true);
	wxGetApp().getMainFrame()->GetStatusBar()->SetStatusText(wxT("Game finished"));
}

/*virtual*/
GameFinishedGameStateController::~GameFinishedGameStateController()
{
	// Nothing to do yet
}

//
// Methods inherited from Controller
//

void GameFinishedGameStateController::handleMouseDown(const wxPoint&)
{
	// Nothing to do
}

void GameFinishedGameStateController::handleMouseUp(const wxPoint&)
{
	// Nothing to do
}

bool GameFinishedGameStateController::handleMouseMotion(const wxPoint&)
{
	// Nothing to do
	return false;
}

const wxBitmap& GameFinishedGameStateController::getBitmapToPaint() const
{
	return mStaticDrawController.getBitmapToPaint();
}

wxBitmap& GameFinishedGameStateController::getBitmapToDraw()
{
	return mStaticDrawController.getBitmapToDraw();
}

//
// Methods inherited from GameStateController
//

void GameFinishedGameStateController::handleSocketConnection(wxSocketEvent& /*socketEvent*/)
{
	wxSocketServer* serverSocket = static_cast<wxSocketServer*>(wxGetApp().getServerSocket());
	SmartPointer<NetworkEventData> data = new NetworkEventData();

	wxASSERT_MSG(serverSocket != NULL, wxT("GameStartedGameStateController::handleSocketConnection called on client side. Could not happen!"));
	data->rejectConnection(serverSocket);
}

void GameFinishedGameStateController::handleSocketLost(wxSocketEvent& socketEvent)
{
	wxSocketBase* socket = wxGetApp().getClientSocket();
	wxSocketBase* serverSocket = wxGetApp().getServerSocket();
	IGameController* gameController = wxGetApp().getMainFrame()->getMainPanel()->getGameController();
	MainFrame::DialogMessageType dialogMessageType = MainFrame::SERVER_ERROR;

	// If the disconnection is on an other socket, there is nothing to do (very unlikely)
	if(socketEvent.GetSocket() != socket)
		return;
	// The remote side has been disconnected
	socket->Destroy();
	socket = NULL;
	wxGetApp().setClientSocket(NULL);
	if(NULL == serverSocket)
		dialogMessageType = MainFrame::CLIENT_ERROR;
	wxGetApp().getMainFrame()->showMessageDialog(wxT("Connection lost!"), dialogMessageType);
	// If we are the client part, we need to revert back to Idle state
	if(NULL == serverSocket)
	{
		gameController->changeState(new IdleGameStateController());

		return;
	}
	// If we are the server part we should continue for waiting for incoming connections
	gameController->changeState(new ServerStartingGameStateController(wxGetApp().getActualLevel()));
}

void GameFinishedGameStateController::handleSocketInput(wxSocketEvent& socketEvent)
{
	SmartPointer<NetworkEventData> data = NULL;
	wxSocketBase* socket = wxGetApp().getClientSocket();
	// TODO: In error cases this pointer can cause memory leakage
	ClientStartingGameStateController* clientStartingController = NULL;
	IGameController* gameController = wxGetApp().getMainFrame()->getMainPanel()->getGameController();

	// If this event is not happened on our socket, there is nothing to do.
	if(socketEvent.GetSocket() != socket)
		return;
	data = new NetworkEventData();
	if(false == data->read(socket))
		return;
	switch(data->getDataType())
	{
		case NetworkEventData::RESTART:
			wxGetApp().getMainFrame()->getMainPanel()->getGameController()->finish(IGameController::RESTART_FROM_REMOTE_SIDE);
			break;
		case NetworkEventData::KICK_OFF:
			// We have been kicked off from the server. Inform the user before the connection is closed
			// The server will close the connection
			wxASSERT_MSG(NULL == wxGetApp().getServerSocket(), wxT("Kick off message received on server side!"));
			wxGetApp().getMainFrame()->showMessageDialog(wxT("The server kicked you off"), MainFrame::CLIENT_ERROR);
			break;
		case NetworkEventData::NEW_LEVEL:
			wxASSERT_MSG(NULL == wxGetApp().getServerSocket(), wxT("Invalid message received on server side"));
			wxGetApp().setActualLevel(data->getStringData());
			// The ClientStarting object will handle the configuration negotiation, not the connection itself
			// So there is no need to provide it with real host and port number
			clientStartingController = new ClientStartingGameStateController(wxT(""), 0);
			// Check if the level is known at our side
			if(NULL != wxGetApp().getConfiguration()->getLevels()->getLevel(wxGetApp().getActualLevel()))
			{
				// Send the acknowledge and change for ClientStarting state to handle configuration negotiation
				data = new NetworkEventData();
				data->setDataType(NetworkEventData::NEW_LEVEL_ACK);
				if(false == data->write(socket))
				{
					socket->Destroy();
					socket = NULL;
					wxGetApp().setClientSocket(NULL);
					wxGetApp().getMainFrame()->showMessageDialog(wxT("Could not send acknowledge to the server!"), MainFrame::CLIENT_ERROR);
					gameController->changeState(new IdleGameStateController());

					return;
				}
				gameController->changeState(clientStartingController);
			}
			else
			{
				// If we are allowed to download unknown levels, lets start it
				if(true ==  wxGetApp().getConfiguration()->getNetworkConfiguration()->downloadUnknownLevels())
					gameController->changeState(new LevelDownloadingGameStateController(clientStartingController));
				else
				{
					// Reject the new level request and show an error message to the user
					data = new NetworkEventData();
					data->setDataType(NetworkEventData::NEW_LEVEL_REJECT);
					// No error handling since we are going to close the connection in any way
					data->write(socket);
					socket->Destroy();
					socket = NULL;
					wxGetApp().setClientSocket(NULL);
					wxGetApp().getMainFrame()->showMessageDialog(wxT("Could not change to new level, because it is unknown, and download is disabled!"), MainFrame::CLIENT_ERROR);
					gameController->changeState(new IdleGameStateController());
				}
			}
			break;
		default:
			wxASSERT_MSG(false, wxT("LocalTurnSubStateController::handleSocketinput called with invalid data type - other than RESTART!"));
			break;
	}
}

void GameFinishedGameStateController::handleSocketOutput(wxSocketEvent& socketEvent)
{
	wxASSERT_MSG(false, wxT("GameFinishedGameStateController::handleSocketOutput() invoked. It could not happen!"));
}

